package com.henry.base.concurrency;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.StampedLock;

public class StampedLock1 {
    static StampedLock lock = new StampedLock();
    static int num1 = 0;
    static int num2 = 0;
    static final int times = 10000;

    public static class WriteThread implements Runnable {
        @Override
        public void run() {
            long l = System.nanoTime();
            for (int i = 0; i < times; i++) {
                long stamp = lock.writeLock();
                try {
                    num1++;
                    num2++;
                } finally {
                    lock.unlockWrite(stamp);
                }
            }
            long l1 = System.nanoTime();
            System.out.println("write time " + (l1 - l) / 1000 / 1000 + "ms");
        }
    }

    public static class StampedReadThread implements Runnable {
        @Override
        public void run() {
            long l = System.nanoTime();
            for (int i = 0; i < times; i++) {
                long stamp = lock.tryOptimisticRead();
                int currNum1 = num1;
                int currNum2 = num2;
                if (!lock.validate(stamp)) {
                    stamp = lock.readLock();
                    try {

                        currNum1 = num1;
                        currNum2 = num2;
                    } finally {

                        lock.unlockRead(stamp);
                    }
                }
            }
            long l1 = System.nanoTime();
            System.out.println("stamped read time " + (l1 - l) / 1000 / 1000 + "ms");

//            System.out.println("read "+num1+"---"+num2);
        }
    }

    public static class ReadThread implements Runnable {
        @Override
        public void run() {
            long l = System.nanoTime();
            for (int i = 0; i < times; i++) {
                long stamp = lock.readLock();
                try {
                    int currNum1 = num1;
                    int currNum2 = num2;
                } finally {
                    lock.unlockRead(stamp);
                }
            }
            long l1 = System.nanoTime();
            System.out.println("read time " + (l1 - l) / 1000 / 1000 + "ms");

//            System.out.println("read "+num1+"---"+num2);
        }

        public static void main(String[] args) throws InterruptedException {
            WriteThread writeThread = new WriteThread();
//            StampedReadThread readThread = new StampedReadThread();
            ReadThread readThread = new ReadThread();
            Thread[] threads = new Thread[21];
            threads[0] = new Thread(writeThread);

            for (int i = 1; i < 21; i++) {
                threads[i] = new Thread(readThread);
            }
            for (int i = 0; i < 21; i++) {
                threads[i].start();
            }

            for (int i = 0; i < 21; i++) {
                threads[i].join();
            }
            System.out.println("end...");
        }
    }

}
